#include <stdio.h>

#include "fl64_add.h"

double ullong_to_double(unsigned long long x) {
    union {
        double d;
        unsigned long long ll;
    } t;

    t.ll = x;
    return t.d;
}

const float64 a_input[46] = {
    0x7FF8000000000000ULL, 0x7FF0000000000000ULL, 0x4000000000000000ULL,
    0x4000000000000000ULL, 0x3FF0000000000000ULL, 0x3FF0000000000000ULL,
    0x0000000000000000ULL, 0x3FF8000000000000ULL, 0x7FF8000000000000ULL,
    0x7FF0000000000000ULL, 0x0000000000000000ULL, 0x3FF8000000000000ULL,
    0xFFF8000000000000ULL, 0xFFF0000000000000ULL, 0xC000000000000000ULL,
    0xC000000000000000ULL, 0xBFF0000000000000ULL, 0xBFF0000000000000ULL,
    0x8000000000000000ULL, 0xBFF8000000000000ULL, 0xFFF8000000000000ULL,
    0xFFF0000000000000ULL, 0x8000000000000000ULL, 0xBFF8000000000000ULL,
    0x7FF8000000000000ULL, 0x7FF0000000000000ULL, 0x3FF0000000000000ULL,
    0x3FF0000000000000ULL, 0x3FF0000000000000ULL, 0x0000000000000000ULL,
    0x3FF8000000000000ULL, 0x7FF8000000000000ULL, 0x7FF0000000000000ULL,
    0x3FF0000000000000ULL, 0x4000000000000000ULL, 0xFFF0000000000000ULL,
    0xFFF0000000000000ULL, 0xBFF0000000000000ULL, 0xBFF0000000000000ULL,
    0xBFF0000000000000ULL, 0x8000000000000000ULL, 0xBFF8000000000000ULL,
    0xFFF8000000000000ULL, 0xFFF0000000000000ULL, 0xBFF0000000000000ULL,
    0xC000000000000000ULL};

const float64 b_input[46] = {
    0x3FF0000000000000ULL, 0x3FF0000000000000ULL, 0x0000000000000000ULL,
    0x3FF8000000000000ULL, 0x7FF8000000000000ULL, 0x7FF0000000000000ULL,
    0x4000000000000000ULL, 0x4000000000000000ULL, 0x7FF0000000000000ULL,
    0x7FF0000000000000ULL, 0x0000000000000000ULL, 0x3FF0000000000000ULL,
    0xBFF0000000000000ULL, 0xBFF0000000000000ULL, 0x8000000000000000ULL,
    0xBFF8000000000000ULL, 0xFFF8000000000000ULL, 0xFFF0000000000000ULL,
    0xC000000000000000ULL, 0xC000000000000000ULL, 0xFFF0000000000000ULL,
    0xFFF0000000000000ULL, 0x8000000000000000ULL, 0xBFF0000000000000ULL,
    0xFFF0000000000000ULL, 0xFFF0000000000000ULL, 0xBFF0000000000000ULL,
    0xFFF8000000000000ULL, 0xFFF0000000000000ULL, 0xBFF0000000000000ULL,
    0xC000000000000000ULL, 0xBFF0000000000000ULL, 0xBFF0000000000000ULL,
    0x8000000000000000ULL, 0xBFF8000000000000ULL, 0x7FF8000000000000ULL,
    0x7FF0000000000000ULL, 0x3FF0000000000000ULL, 0x7FF8000000000000ULL,
    0x7FF0000000000000ULL, 0x3FF0000000000000ULL, 0x4000000000000000ULL,
    0x3FF0000000000000ULL, 0x3FF0000000000000ULL, 0x0000000000000000ULL,
    0x3FF8000000000000ULL};

const float64 z_output[46] = {
    0x7FF8000000000000ULL, 0x7FF0000000000000ULL, 0x4000000000000000ULL,
    0x400C000000000000ULL, 0x7FF8000000000000ULL, 0x7FF0000000000000ULL,
    0x4000000000000000ULL, 0x400C000000000000ULL, 0x7FF8000000000000ULL,
    0x7FF0000000000000ULL, 0x0000000000000000ULL, 0x4004000000000000ULL,
    0xFFF8000000000000ULL, 0xFFF0000000000000ULL, 0xC000000000000000ULL,
    0xC00C000000000000ULL, 0xFFF8000000000000ULL, 0xFFF0000000000000ULL,
    0xC000000000000000ULL, 0xC00C000000000000ULL, 0xFFF8000000000000ULL,
    0xFFF0000000000000ULL, 0x8000000000000000ULL, 0xC004000000000000ULL,
    0x7FF8000000000000ULL, 0x7FFFFFFFFFFFFFFFULL, 0x0000000000000000ULL,
    0xFFF8000000000000ULL, 0xFFF0000000000000ULL, 0xBFF0000000000000ULL,
    0xBFE0000000000000ULL, 0x7FF8000000000000ULL, 0x7FF0000000000000ULL,
    0x3FF0000000000000ULL, 0x3FE0000000000000ULL, 0x7FF8000000000000ULL,
    0x7FFFFFFFFFFFFFFFULL, 0x0000000000000000ULL, 0x7FF8000000000000ULL,
    0x7FF0000000000000ULL, 0x3FF0000000000000ULL, 0x3FE0000000000000ULL,
    0xFFF8000000000000ULL, 0xFFF0000000000000ULL, 0xBFF0000000000000ULL,
    0xBFE0000000000000ULL};

int main() {
    int main_result;
    int i;
    float64 x1, x2;
    main_result = 0;
    for (i = 0; i < 46; i++) {
        float64 result;
        x1 = a_input[i];
        x2 = b_input[i];
        result = float64_add(x1, x2);
        main_result += (result != z_output[i]);

        printf(
            "a_input=%016llx b_input=%016llx expected=%016llx "
            "output=%016llx (%lf)\n",
            a_input[i],
            b_input[i],
            z_output[i],
            result,
            ullong_to_double(result));
    }

    if (main_result) {
        fprintf(stderr, "Benchmark results are incorrect\n");
        return -1;
    }

    printf("Success.\n");
    return 0;
}
